package org.budo.graph.service.util;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.budo.graph.Constant;
import org.budo.support.freemarker.FreemarkerUtil;
import org.budo.support.lang.util.MapUtil;
import org.budo.support.lang.util.ReflectUtil;
import org.budo.support.lang.util.StringUtil;
import org.budo.support.servlet.util.QueryStringUtil;
import org.budo.support.spring.io.util.ResourceUtil;
import org.budo.support.spring.util.SpringUtil;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.support.ScheduledMethodRunnable;

import lombok.extern.slf4j.Slf4j;

/**
 * @author lmw
 * 
 * @see org.springframework.scheduling.config.TaskNamespaceHandler
 * @see org.springframework.scheduling.config.CronTask
 * @see org.springframework.scheduling.support.ScheduledMethodRunnable
 */
@Slf4j
public class SpringTaskUtil {
    private static final String DUBBO_DRUID_FM_SPRING_TASK_HTM = Constant.GRAPH_TEMPLATE_PATH + "/spring-task.htm";

    public static String writeSpringTaskResponse(ApplicationContext applicationContext, String url) {
        Map<String, String> parameters = QueryStringUtil.queryStringToStringMap(url);
        String action = StringUtil.trim(parameters.get("action"));

        if ("invoke".equals(action)) {
            return invoke(applicationContext, url);
        }

        return list(applicationContext, url);
    }

    private static String list(ApplicationContext applicationContext, String url) {
        List<String> beanNames = SpringUtil.getBeanNamesForType(applicationContext, ScheduledMethodRunnable.class);

        List scheduledMethods = new ArrayList<>();

        for (String beanName : beanNames) {
            ScheduledMethodRunnable scheduledMethod = (ScheduledMethodRunnable) SpringUtil.getBean(applicationContext, beanName);
            Map<String, Object> map = MapUtil.stringObjectMap("scheduledMethod", scheduledMethod, //
                    "beanType", ReflectUtil.beanType(scheduledMethod.getTarget().getClass()).getName(), //
                    "methodName", scheduledMethod.getMethod().getName());
            scheduledMethods.add(map);
        }

        Map<String, Object> map = MapUtil.stringObjectMap("scheduledMethods", scheduledMethods);

        String inputString = ResourceUtil.classPathResourceInputStreamToString(DUBBO_DRUID_FM_SPRING_TASK_HTM);
        return FreemarkerUtil.freemarkerRender(inputString, map);
    }

    private static String invoke(ApplicationContext applicationContext, String url) {
        log.info("#60 invoke, applicationContext=" + applicationContext + ", url=" + url);

        Map<String, String> parameters = QueryStringUtil.queryStringToStringMap(url);
        String beanType = StringUtil.trim(parameters.get("beanType"));
        String methodName = StringUtil.trim(parameters.get("methodName"));

        Class type = ReflectUtil.classForName(beanType);
        Object bean = SpringUtil.getBean(type);
        Object result = ReflectUtil.invokeMethod(type, methodName, new Class[0], bean, new Object[0]);

        log.info("#70 after invokeMethod, result=" + result + ", methodName=" + methodName + ", bean=" + bean);

        return "done";
    }
}